#include <stdio.h>
#include <stdlib.h>
#include <sys/fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include "fiemap.h" //This is from https://github.com/coreutils/coreutils/blob/df88fce71651afb2c3456967a142db0ae4bf9906/src/fiemap.h

int main(int argc, char* argv[]) {

    int input_fd;
    int extents_size = 0;

    if(argc != 2){
        printf ("Usage: ioctl file1");
        return 1;
    }

    /* Create input file descriptor */
    input_fd = open (argv [1], O_RDWR);
    if (input_fd < 0) {
            perror ("open");
            return 2;
    }

    struct fiemap *fiemap;
    if ((fiemap = (struct fiemap*)malloc(sizeof(struct fiemap))) == NULL) {
        fprintf(stderr, "Out of memory allocating fiemap\n");
        return NULL;
    }
    memset(fiemap, 0, sizeof(struct fiemap));

    fiemap->fm_start = 0;
    fiemap->fm_flags = 0;
    fiemap->fm_extent_count = 0;
    fiemap->fm_length = ~0;
    fiemap->fm_mapped_extents = 0;

    if (ioctl(input_fd, FS_IOC_FIEMAP, fiemap) < 0) {
        fprintf(stderr, "fiemap ioctl() failed\n");
        return NULL;
    }


    printf("------------------------------------------------\n");       
    printf("The first time to print the layout of this file.\n");
    printf("1 fiemap->fm_start:%lx\n",fiemap->fm_start);
    printf("2 fiemap->fm_length:%lx\n",fiemap->fm_length);
    printf("3 fiemap->fm_flags:%x\n",fiemap->fm_flags);
    printf("4 fiemap->fm_mapped_extents:%x\n",fiemap->fm_mapped_extents);
    printf("5 fiemap->fm_extent_count:%x\n",fiemap->fm_extent_count);
    printf("6 fiemap->fm_reserved:%x\n",fiemap->fm_reserved);
    printf("7 fiemap->fm_extents[0].fe_logical:%lx\n",fiemap->fm_extents[0].fe_logical);
    printf("8 fiemap->fm_extents[0].fe_physical:%lx\n",fiemap->fm_extents[0].fe_physical);
    printf("9 fiemap->fm_extents[0].fe_length:%lx\n",fiemap->fm_extents[0].fe_length);
    printf("10 fiemap->fm_extents[0].fe_reserved64[0]:%lx\n",fiemap->fm_extents[0].fe_reserved64[0]);
    printf("11 fiemap->fm_extents[0].fe_reserved64[1]:%lx\n",fiemap->fm_extents[0].fe_reserved64[1]);
    printf("12 fiemap->fm_extents[0].fe_flags:%lx\n",fiemap->fm_extents[0].fe_flags);
    printf("13 fiemap->fm_extents[0].fe_reserved[0]:%lx\n",fiemap->fm_extents[0].fe_reserved[0]);
    printf("14 fiemap->fm_extents[0].fe_reserved[1]:%lx\n",fiemap->fm_extents[0].fe_reserved[1]);
    printf("15 fiemap->fm_extents[0].fe_reserved[2]:%lx\n",fiemap->fm_extents[0].fe_reserved[2]);

    //重新根据第一次结果分配正确大小的内存空间用于接收fiemap
    extents_size = sizeof(struct fiemap_extent)*(fiemap->fm_mapped_extents);

    if ((fiemap = (struct fiemap*)realloc(fiemap,sizeof(struct fiemap)+extents_size)) == NULL) { 
        fprintf(stderr, "Out of memory allocating fiemap\n");
        return NULL;
    }

    memset(fiemap->fm_extents, 0, extents_size);
    fiemap->fm_extent_count = fiemap->fm_mapped_extents;
    fiemap->fm_mapped_extents = 0;

    if (ioctl(input_fd, FS_IOC_FIEMAP, fiemap) < 0) {
        fprintf(stderr, "fiemap ioctl() failed\n");
        return NULL;
    }

    printf("------------------------------------------------\n");  
    printf("The second time to print the layout of this file.\n");
    printf("1 fiemap->fm_start:%lx\n",fiemap->fm_start);
    printf("2 fiemap->fm_length:%lx\n",fiemap->fm_length);
    printf("3 fiemap->fm_flags:%x\n",fiemap->fm_flags);
    printf("4 fiemap->fm_mapped_extents:%x\n",fiemap->fm_mapped_extents);
    printf("5 fiemap->fm_extent_count:%x\n",fiemap->fm_extent_count);
    printf("6 fiemap->fm_reserved:%x\n",fiemap->fm_reserved);
    printf("--------\n"); 
    printf("7 fiemap->fm_extents[0].fe_logical:%lx\n",fiemap->fm_extents[0].fe_logical);
    printf("8 fiemap->fm_extents[0].fe_physical:%lx\n",fiemap->fm_extents[0].fe_physical);
    printf("9 fiemap->fm_extents[0].fe_length:%lx\n",fiemap->fm_extents[0].fe_length);
    printf("7 fiemap->fm_extents[1].fe_logical:%lx\n",fiemap->fm_extents[1].fe_logical);
    printf("8 fiemap->fm_extents[1].fe_physical:%lx\n",fiemap->fm_extents[1].fe_physical);
    printf("9 fiemap->fm_extents[1].fe_length:%lx\n",fiemap->fm_extents[1].fe_length);
    printf("7 fiemap->fm_extents[2].fe_logical:%lx\n",fiemap->fm_extents[2].fe_logical);
    printf("8 fiemap->fm_extents[2].fe_physical:%lx\n",fiemap->fm_extents[2].fe_physical);
    printf("9 fiemap->fm_extents[2].fe_length:%lx\n",fiemap->fm_extents[2].fe_length);
    printf("7 fiemap->fm_extents[3].fe_logical:%lx\n",fiemap->fm_extents[3].fe_logical);
    printf("8 fiemap->fm_extents[3].fe_physical:%lx\n",fiemap->fm_extents[3].fe_physical);
    printf("9 fiemap->fm_extents[3].fe_length:%lx\n",fiemap->fm_extents[3].fe_length);

    /* Close file descriptors */
    close (input_fd);

    return 0;
}